package org.firefly.db.dialect;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.firefly.db.meta.ColumnMeta;
import org.firefly.db.meta.TableMeta;

/**
 * SQL Server2005 数据库方言
 * @author firefly
 *
 */
public class MySQLDialect extends DialectImpl {
	private static Map<Integer,String> types = new HashMap<Integer,String>();
	
	static{
		types.put(Types.CHAR, "char");   //1
		types.put(Types.VARCHAR, "varchar"); //12
		types.put(Types.NUMERIC, "float"); //2
		types.put(Types.DECIMAL, "decimal");//3
		types.put(Types.INTEGER, "int"); //4
		types.put(Types.BIGINT, "bigint"); //-5
		types.put(Types.FLOAT, "float"); //6
		types.put(Types.DOUBLE, "float"); //8
		types.put(Types.NVARCHAR, "varchar"); //-9
		types.put(Types.CLOB, "text"); //2005
		types.put(Types.BLOB, "blob"); //2004
		types.put(Types.BIT, "bit"); //-7
		types.put(Types.VARBINARY, "int"); //-3
		types.put(Types.DATE, "date"); //91
		types.put(Types.TIMESTAMP, "datetime"); //93
		types.put(Types.LONGVARCHAR, "text"); //-1
		
		types.put(Types.LONGVARBINARY, "blob"); //image -4
		types.put(Types.TINYINT, "tinyint"); //-6
		types.put(Types.BINARY, "timestamp"); //-2
		
	}

	@Override
	public String processSQLVal(Object val,int javaType, ColumnMeta cm){
		if(val==null)return "NULL";
		try {
			switch(javaType){
				case Types.CHAR: 
				case Types.CLOB:
				case Types.NVARCHAR:
				case Types.VARCHAR: return processStr(String.valueOf(val));
				case Types.NUMERIC: 
				case Types.DECIMAL: if(val instanceof String){return val.toString();}else{return BigDecimal.class.cast(val).toString();}
				case Types.INTEGER: return Integer.class.cast(val).toString();
				case Types.BIGINT: return Long.class.cast(val).toString();
				case Types.FLOAT: return Float.class.cast(val).toString();
				case Types.BIT:  return Boolean.class.cast(val)?"1":"0";
				case Types.DATE: 
					if(String.class.isInstance(val)){
						return "'"+val.toString()+"'";
					}else if(Date.class.isInstance(val)){
						return "'"+dateSDF.format((Date)val)+"'";
					}
				case Types.TIMESTAMP:
					if(String.class.isInstance(val)){
						return "'"+val.toString()+"'";
					}else if(Date.class.isInstance(val)){
						return "'"+dateTimeSDF.format((Date)val)+"'";
					}
				case Types.VARBINARY:
				case Types.BLOB:
				default:return "NULL";
			}
		} catch (ClassCastException e) {
			e.printStackTrace();
		}
		return "NULL";
	}

	@Override
    public int getLength(int javaType, int length){
	    if(javaType == Types.TIMESTAMP){
	        return 6;//能够存储年月日 时分秒的格式
	    }
        return length;
    }
	
	/**
     * 字符串处理，增加转义符
     * @param a
     * @return
     */
    public String processStr(String a){
        if(a != null && a.contains("\\")){
            a = a.replace("\\", "\\\\");
        }
        return super.processStr(a);
    }
	
	@Override
	public boolean columnTypeHasDecimal(int javaType){
		switch(javaType){
			case Types.DECIMAL: 
			case Types.NUMERIC: return true;
			default:return false;
		}
	}
	
	@Override
	public boolean columnTypeHasLength(int javaType){
		switch(javaType){
			case Types.CHAR:  
			case Types.VARCHAR: 
			case Types.NVARCHAR: 
			case Types.DECIMAL:
			case Types.NUMERIC: return true;
			
			case Types.TIMESTAMP: 
			case Types.VARBINARY:
			case Types.INTEGER: 
			case Types.CLOB:
			case Types.DATE: 
			case Types.BLOB:
			default:return false;
		}
	}
	
	@Override
	public boolean columnTypeHasLength(ColumnMeta cm,int javaType){
	    return columnTypeHasLength(javaType);
	}
	
	@Override
	protected Map<Integer,String> getTypes() {
		return types;
	}
	
	@Override
	public String getNamingChar() {
		return "`";
	}
	
	@Override
	public String getConcatStr(String a,String b){
		return "concat("+a+","+b+")";
	}
	
	@Override
	public int maxCols() {
		return 100;
	}
	//为clob列提供多次update进行数据插入。
	private static final String COLB_INSERT_SQL="update [tablename] set [colbName] = [colPartVal] where [pkName]=[pkVal]";
	public List<String> buildClobSql(TableMeta targetTM, String columnName, Map<String,Object> val) throws SQLException {
		List<String> colbSQLs = new ArrayList<String>(); 
		String colVal = String.valueOf(val.get(columnName));
		String pkName = targetTM.getPKname();
		Object pkVal = val.get(pkName);
		if(pkName==null || "".equals(pkName.trim())){
			throw new SQLException("没有为表["+targetTM.getName()+"]提供主键列！请补充后再进行数据处理！");
		}
		String colbSQL = COLB_INSERT_SQL.replace("[tablename]", targetTM.getName()).replace("[colbName]", columnName)
					.replace("[pkName]", pkName).replace("[pkVal]", processStr(pkVal.toString()));
		int m = 500;
		for (int k = 0; k < colVal.length() ; k+=m) {  
			int len = colVal.length()-k;
			String partVal = colVal.substring(k, k+(len>m?m:len));
			colbSQLs.add(colbSQL.replace("[colPartVal]", getConcatStr("CAST("+columnName+"  AS CHAR)", processStr(partVal))));
		}
		return colbSQLs;
	}

	@Override
	public String getPaginationSql(String selectSql,
			String tablename,
			String tAlias,
			String pk,
			String fromTableSql,
			String orderBySql,String whereSql, int curPageNo, int pageSize) {
		String sql = selectSql + fromTableSql + whereSql + orderBySql;
		return new StringBuffer("select * from (").append(sql).append(") pagination_a limit ").append((curPageNo-1)*pageSize).append(",").append(pageSize).toString();
	}

	@Override
	public String getModifyColumnKey() {
		return "";
	}
}
